package org.xq.softcup.mq.remoting.net.params;

import org.xq.softcup.mq.remoting.invoker.XQRpcInvokerFactory;
import org.xq.softcup.mq.remoting.invoker.call.XQRpcInvokeCallback;
import org.xq.softcup.mq.util.XQRpcException;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class XQRpcFutureResponse implements Future<XQRpcResponse> {
    private XQRpcInvokerFactory invokerFactory;
    private XQRpcRequest request;
    private XQRpcResponse response;
    private boolean done = false;
    private Object lock = new Object();
    private XQRpcInvokeCallback invokeCallback;

    public XQRpcFutureResponse(XQRpcInvokerFactory invokerFactory, XQRpcRequest request, XQRpcInvokeCallback invokeCallback) {
        this.invokerFactory = invokerFactory;
        this.request = request;
        this.invokeCallback = invokeCallback;
        setInvokerFuture();
    }

    public void setInvokerFuture() {
        this.invokerFactory.setInvokerFuture(this.request.getRequestId(), this);
    }

    public void removeInvokerFuture() {
        this.invokerFactory.removeInvokerFuture(this.request.getRequestId());
    }

    public XQRpcRequest getRequest() {
        return this.request;
    }

    public XQRpcInvokeCallback getInvokeCallback() {
        return this.invokeCallback;
    }

    public void setResponse(XQRpcResponse response) {
        this.response = response;
        synchronized (this.lock) {
            this.done = true;
            this.lock.notifyAll();
        }
    }

    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    public boolean isCancelled() {
        return false;
    }

    public boolean isDone() {
        return this.done;
    }

    public XQRpcResponse get() throws InterruptedException, ExecutionException {
        try {
            return get(-1L, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            throw new XQRpcException(e);
        }
    }

    public XQRpcResponse get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        if (!this.done) {
            synchronized (this.lock) {
                try {
                    if (timeout < 0L) {
                        this.lock.wait();
                    } else {
                        long timeoutMillis = TimeUnit.MILLISECONDS == unit ? timeout : TimeUnit.MILLISECONDS.convert(timeout, unit);
                        this.lock.wait(timeoutMillis);
                    }
                } catch (InterruptedException e) {
                    throw e;
                }
            }
        }
        if (!this.done) {
            throw new XQRpcException("请求超时:" + System.currentTimeMillis() + ", request:" + this.request.toString());
        }
        return this.response;
    }
}
